//============================================================================
// Name        : SocketClientMain.cpp.cpp
// Author      : Ge LIang
// Version     :
// Copyright   : @2016 GeLiang
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;

#include <stdlib.h>
#include <string.h>

#include "common.h"
#include "SocketClient.h"
#include "GWSocketHandler.h"
#include "SocketLooper.h"
#include "cJSON.h"
#include "base64er.h"
#include "Hex.h"
#include "cJSON_Utils.h"
#include "BaseAdapter.h"

EXPORT void login(int userID, const char* token, void* client) {
    if (client==NULL)
    {
        LOGW("client is null");
        return;
    }
	GWLogin req;
	int lenFieldHeader = sizeof(GWLogin);
	memset(&req, 0, lenFieldHeader);
	req.header.cmd = 2501;
	req.header.size = lenFieldHeader;
	req.userid = userID;
	memset(req.token, 0, 32);
	memcpy(req.token, token, strlen(token));
	((SocketLooper*) client)->putToSend((char*) (&req), req.header.size);
}
EXPORT void heartbeat(void* client) {
    if (client == NULL)
    {
        LOGW("client is null");
        return;
    }
	GWNullMsg req;
	int lenHeader = sizeof(GWHeader);
	memset(&req, 0, lenHeader);
	req.header.cmd = 2502;
	req.header.size = lenHeader;
	((SocketClient*) client)->send((char*) (&req), req.header.size);
}
EXPORT int sendMsgToAll(char* buf, int size, void* client) {
    if (client == NULL)
    {
        LOGW("client is null");
        return 0;
    }
	if (buf == NULL) {
		return 0;
		LOGW("null Buffer will not be send");
	};
	int packetSize = sizeof(GWMsg) + size;
	GWMsg* req = (GWMsg*) malloc(packetSize);
	if (req == NULL) {
		return 0;
		LOGE("xx OOM xx");
	};
	memset(req, 0, packetSize);
	req->header.cmd = 112;
	req->header.size = packetSize;
	memcpy(req + 1, buf, size);
//	LOGI("send msg %d:%s", req->header.cmd, req + 1);
	((SocketLooper*) client)->putToSend((char*) (req), req->header.size);
	free(req);
	return packetSize;
}
bool isInit = false;
EXPORT int sendJson(char* input, int inputSize, void* client) {
    if (client == NULL)
    {
        LOGW("client is null");
        return -1;
    }
    if (!isInit)
    {
    initMethodBirdge();
    isInit = true;
    }
	return invokeMethod(input, inputSize, client);
}

int handleGWPacket(Packet* packet) {
	GWHeader* header = (GWHeader*) packet->data;
	switch (header->cmd) {
	case 2508:
		LOGI("login success");
		break;
	case 110:
		if (header->size - sizeof(GWHeader) < 1024) {
			char buffer[1024];
			memset(buffer, 0, 1024);
			memcpy(buffer, header + 1, header->size - sizeof(GWHeader));
			LOGI("xxxxxxxxxxxxxxxxxxxxxxxxx");
			LOGI("RECV a message :%s", buffer);
			LOGI("xxxxxxxxxxxxxxxxxxxxxxxxx");
		} else {
			LOGW("RECV a message ,but size>1000");
		}
		break;
	default:
		break;
	};
	return packet->size;
}

EXPORT void* createTcpSocketClient(char* host, int hostSize, int port,
		int recvTimeout, int socketTag) {
	if (host == NULL || hostSize >= 1024 || hostSize < 0) {
		LOGE("host is err");
		return 0;
	}
	char tempbuf[1024];
	memset(tempbuf, 0, 1024);
	memcpy(tempbuf, host, hostSize);
	SocketLooper* loop = new SocketLooper(tempbuf, port, recvTimeout,
			socketTag);
	return (void*) loop;
}

SyncQueue<Packet*> recvQueue;
int isClose = 0;
int handleRecvPorxy(Packet* recvPacket) {
	if (recvPacket == NULL) {
		return 0;
	}

	Packet* cachePacket = (Packet*) malloc(sizeof(Packet));
	if (cachePacket == null) {
		return ERR_OOM;
	}
	if (recvQueue.size() > 1024) {
		LOGI("OOM ' recvQueue.size()>1024'");
		return ERR_OOM;
	}
	memset(cachePacket, 0, sizeof(Packet));
	memcpy(cachePacket->data, recvPacket->data, recvPacket->size);
	cachePacket->size = recvPacket->size;
	LOGI("recv packet[%d] ->%s<-", cachePacket->size,
			(char* )(((GWNullMsg* )cachePacket->data) + 1));
	recvQueue.push(cachePacket);
	return 0;
}
int U3D_RecvJson(Packet* packet1) {
	if (packet1 == NULL) {
		return 0;
	}

	int JsonLen = packet1->size ;
	char json[4096];
	memset(json, 0, 4096);
	memcpy(json, packet1->data,JsonLen);
	LOGI("recv a JSON[%d] ->%s<-", JsonLen,json);
	return 0;
}
int handleSocketCloseProxy(int tag) {
	LOGW("socket client had close tag %d", tag);
	isClose = tag;
	return 0;
}

EXPORT void startLoop(void* loop, handlePacket handler,
		handleSocketClosed handler1) {
	if (loop != NULL) {
		((SocketLooper*) loop)->setRecvHandler(handleRecvPorxy,
				handleSocketCloseProxy);
		((SocketLooper*) loop)->startLoop();
	}

}
EXPORT int tryRecvPacket(handlePacket handler) {
	Packet * packet = NULL;
	while ((packet = recvQueue.pop()) != NULL) {
		handler(packet);
		free(packet);
		packet = NULL;
	}
	if (isClose != 0) {
		LOGW("socket %d isClose ", isClose);
		isClose = 0;
		return isClose;
	}
	return 0;
}
EXPORT int tryRecvJsonPacket(handlePacket handler) {
	Packet * packet = NULL;
	while ((packet = recvQueue.pop()) != NULL) {
		GWHeader* head = ((GWHeader*) (packet->data));
		LOGI("recv packet head->cmd %d head->size %d", head->cmd,head->size);
		if (head->cmd == CMD_SingleMsg) {
			cJSON* jo1 = cJSON_CreateObject();
			if (jo1 == NULL) {
				LOGW("OOM cJSON_CreateObject fail");
				return 0;
			}
			LOGI("CMD:%d", head->cmd);
			cJSON_AddNumberToObject(jo1, "action", CMD_SendToAll);
			cJSON_AddStringToObject(jo1, "msg", "");

			//to base64
			int bytesLen = packet->size - sizeof(GWHeader);
			int bytebase64Len = bytesLen*2;
			char byteHex[BUF_MAX_SIZE];
			memset(byteHex, 0, BUF_MAX_SIZE);
			bytesToString((char*) (packet->data + sizeof(GWHeader)),
					bytesLen, byteHex,bytebase64Len);
			cJSON_AddStringToObject(jo1, "bytes", byteHex);

			//to json string
			char * stringJSON = cJSON_PrintUnformatted(jo1);
			if (strlen(stringJSON) > BUF_MAX_SIZE) {
				LOGW("Json Len > BUF_MAX_SIZE[%d]", BUF_MAX_SIZE);
				return 0;
			}
			LOGI("toJSON %s", stringJSON);
			Packet packetJSON;
			memset(packetJSON.data, 0, BUF_MAX_SIZE);
			memcpy(packetJSON.data, stringJSON, strlen(stringJSON));
			packetJSON.size = strlen(stringJSON);
			handler(&packetJSON);
		} else {
			LOGW("unknown packet: head->cmd %d head->size %d", head->cmd,head->size);
		}
		free(packet);
		packet = NULL;
	}
	if (isClose != 0) {
		LOGW("socket %d isClose ", isClose);
		isClose = 0;
		return isClose;
	}
	return 0;
}

EXPORT void destorySocketClient(void * client) {
    if (client == NULL)
    {
        LOGW("client is null");
        return;
    }
	((SocketLooper*) client)->stopLoop();
	delete (((SocketLooper*) client));
}

EXPORT int tryRecv(handlePacket handler, void * client) {
    if (client == NULL)
    {
        LOGW("client is null");
        return 0;
    }
	//Packet packet;
	//memset(&packet, 0, sizeof(packet));
	//(*handler)(&packet);
	//return 0;
	return ((SocketClient*) client)->recv(handler);
}



void testGetRoomList(int userID, void * client)
{
    cJSON* jo = cJSON_CreateObject();
    cJSON* msg = cJSON_CreateObject();
    cJSON_AddNumberToObject(msg, "cmd", CMD_GROUP_LIST);
    cJSON_AddNumberToObject(msg, "fromID", userID);
    cJSON_AddNumberToObject(msg, "toID", userID);
    cJSON_AddNumberToObject(jo, JSON_BRIDGE_METHID, CMD_MSG_ID_FROM_TO_STRING);
    cJSON_AddItemToObject(jo, JSON_BRIDGE_PARAMS, msg);
    char * json = cJSON_PrintUnformatted(jo);
    sendJson(json, strlen(json), client);
    cJSON_Delete(jo);
}
void testSendMsgToRoom(int userID, void * client)
{
    cJSON* jo = cJSON_CreateObject();
    cJSON* msg = cJSON_CreateObject();
    cJSON_AddNumberToObject(msg, "cmd", CMD_MSG_SEND_GROUP);
    cJSON_AddNumberToObject(msg, "fromID", userID);
    cJSON_AddNumberToObject(msg, "toID", userID);
    cJSON_AddNumberToObject(jo, JSON_BRIDGE_METHID, CMD_MSG_ID_FROM_TO_BYTES);
    cJSON_AddItemToObject(jo, JSON_BRIDGE_PARAMS, msg);
    char* byteData = "Hello!!!";
    char* hexData = (char*)malloc(strlen(byteData) * 2+1);
    memset(hexData, 0, strlen(byteData) * 2+1);
    bytesToString(byteData,strlen(byteData),hexData,strlen(byteData)*2 );

    LOGI("||%s||%s||",byteData,hexData);
    cJSON_AddStringToObject(jo, JSON_BRIDGE_BYTES, hexData);
    char * json = cJSON_PrintUnformatted(jo);
    LOGI("json->%s",json);
    sendJson(json, strlen(json), client);
    cJSON_Delete(jo);
}
int main() {
//	void *client1 = createTcpSocketClient("www.dboomsky.com", 9999, 5,0);
	char* HOST = "192.168.8.155";
	void *client = createTcpSocketClient(HOST, (int) strlen(HOST), 12345, 10,
			0);
	const char* helloword = "hello ";
	int userID = rand();
	LOGI("userID:%d to login",userID);
    initMethodBirdge();
	startLoop(client, handleRecvPorxy, handleSocketCloseProxy);
	login(userID, helloword, client);
    testGetRoomList(userID, client);
    testSendMsgToRoom(userID, client);
	threadSleep(3 * 1000);
	tryRecvJsonPacket(U3D_RecvJson);
	destorySocketClient(client);
	threadSleep(3000);

    getchar();
	return 0;
}

